--controller 入口
local _M = {}

local o = require "models.object"
local upload = require "resty.upload"
local md5 = require "resty.md5"
local cjson = require "cjson"
local uuid = require "util.uuid"
local http_time = ngx.http_time
local resp_header = ngx.header
local ngx_var = ngx.var
local method = ngx.var.request_method
local req_headers = ngx.req.get_headers


local function gen_cache_control_headers(ts)
    resp_header["Last-Modified"] = http_time(tonumber(ts) / 1000)
    resp_header["Cache-Control"] = "max-age=3600"
end
--启动类
function _M.run()
    local uri = ngx_var.uri
    -- if uri == "/" then
    --     resp_header["Cache-Control"] = "max-age=3600"
    --     return ngx.say("static server by openresty")
    -- end

    if uri == "/upload" then
        return _M.upload()
    end

    if "GET" == method then
        return _M.get()
    end

    if "HEAD" == method then
        return _M.head()
    end

    if "POST" == method then
        return _M.post()
    end

    if "DELETE" == method then
        return _M.delete()
    end

end

function getFileExt(res)
    local ext = ""
    local filename = ngx.re.match(res,'(.+)filename="(.+)"(.*)')
    if filename then
        ext = filename[2]:match(".+%.(%w+)$")
    end
    if ext then
        return "." .. ext
    else
        return ""
    end
end

--文件上传接口,
function _M.upload()
    local rh = req_headers()
    if not rh['bucket'] then
        ngx.exit(403)
        return
    end
    local form, err = upload:new()
    if not form then
        ngx.log(ngx.ERR, "failed to new upload: ", err)
        ngx.exit(500)
        return
    end
    form:set_timeout(1000)

    local meta = {}
    local ext = ""
    local blob = ""
    local bucket = rh['bucket']
    ngx.log(ngx.ERR, "bucket is", bucket)
    local obj = o:new(bucket)
    while true do
        local typ, res, err = form:read()
        if not typ then
            ngx.log(ngx.ERR, "failed to read data: ", err)
            ngx.exit(500)
            return
        end
        if typ == "header" then
            if res[1] ~= "Content-Type" then
                ext = getFileExt(res[2])
            else
                meta["contentType"] = res[2]
            end
        elseif typ == "body" then
            blob = blob..res
        elseif typ == "part_end" then
        elseif typ == "eof" then
            break
        else
        end
    end
    local filename = uuid:generate() .. ext
    local f, err = obj:put(filename)
    if not f then
        ngx.log(ngx.ERR, "failed to put object: ", err)
        ngx.exit(500)
        return
    end

    f:write(blob, 0)
    f:update_md5()
    f:update_meta(meta)
    resp_header["Content-Type"] = "application/json"
    ngx.say(cjson.encode({ret=1,bucket=bucket,key=filename}))
    ngx.exit(200)

end

function _M.get()
    local uri = ngx_var.uri
    local m, err = ngx.re.match(uri, "/(?<bn>.*?)/(?<filename>[A-Za-z0-9_\\-/.]+)")
    if m then
        local bn = m["bn"]
        local filename = m["filename"]

        local obj = o:new(bn)
        local dbfile = obj:get(filename)
        if not dbfile then
            ngx.exit(404)
            return
        end
        if dbfile.last_modified then
            gen_cache_control_headers(dbfile.last_modified)
        end
        if dbfile.content_type then resp_header['Content-Type']=dbfile.content_type end
        if dbfile.file_size then resp_header['Content-Length']=dbfile.file_size end
        ngx.say(dbfile:read())
        return
    end
    ngx.exit(404)
end

--OPTIONS 请求，html5跨域请求时先用option请求来判断是否允许跨域
function _M.options()
    resp_header['Access-Control-Allow-Origin']="*"
    resp_header['Access-Control-Allow-Methods']="OPTIONS, HEAD, POST, DELETE"
    ngx.exit(200)
end

function _M.post()
    local uri = ngx_var.uri
    local f, err
    local m, err = ngx.re.match(uri, "/(?<bn>.*?)/(?<filename>[A-Za-z0-9_\\-/.]+)")
    if not m then
        ngx.exit(404)
    end
    local bn = m["bn"]
    local filename = m["filename"]
    local form, err = upload:new()
    local blob = ""
    if not form then
        ngx.log(ngx.ERR, "failed to new upload: ", err)
        ngx.exit(500)
        return
    end
    form:set_timeout(6000)
    local obj = o:new(bn)
    local meta = {}
    f = obj:get(filename)
    if not f then
        f, err = obj:put(filename)
    end
    if not f then
        ngx.log(ngx.ERR, "failed to put object: ", err)
        ngx.exit(500)
        return
    end

    while true do
        local typ, res, err = form:read()
        if not typ then
            ngx.log(ngx.ERR, "failed to read: ", err)
            ngx.exit(500)
            return
        end
        if typ == "header" then
            if res[1] == "Content-Type" then
                meta["contentType"] = res[2]
            end
        end
        if typ == "body" then
            blob = blob..res
        end
        if typ == "eof" then
            break
        end
    end

    f:write(blob, 0)
    f:update_md5()
    f:update_meta(meta)
    ngx.exit(200)
end

function _M.delete()
    local uri = ngx_var.uri
    local m, err = ngx.re.match(uri, "/(?<bn>.*?)/(?<filename>[A-Za-z0-9_\\-/.]+)")
    if not m then
        ngx.exit(404)
    end
    local bn = m["bn"]
    local filename = m["filename"]
    local obj = o:new(bn)
    local ok = obj:delete(filename)
    if ok then
        ngx.exit(200)
    else
        ngx.exit(500)
    end
end

function _M.head()
    local uri = ngx_var.uri
    local m, err = ngx.re.match(uri, "/(?<bn>.*?)/(?<filename>[A-Za-z0-9_\\-/.]+)")
    if m then
        local bn = m["bn"]
        local filename = m["filename"]
        local obj = o:new(bn)
        local dbfile = obj:get(filename)
        if not dbfile then
            ngx.exit(404)
        end
        if dbfile.last_modified then
            gen_cache_control_headers(dbfile.last_modified)
        end
        if dbfile.content_type then resp_header['Content-Type']=dbfile.content_type end
        if dbfile.file_size then resp_header['Content-Length']=dbfile.file_size end
        ngx.exit(200)
    end

    ngx.exit(404)
end

return _M